package com.dtu.distributed.controller;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import com.dtu.distributed.connection.AdminConnection;
import com.dtu.distributed.connection.AdminConnectionImpl;
import com.dtu.distributed.enums.Action;
import com.dtu.distributed.filereader.ReadNodeList;
import com.dtu.distributed.thread.AdminElectionThread;
import com.dtu.distributed.thread.AdminGetAnswerThread;
import com.dtu.distributed.thread.AdminThread;
import com.dtu.distributed.thread.AdminElectionListenerThread;
import com.dtu.distributed.thread.TemperatureThread;

public class BullyAlgorithmControlller {

	
	
	public static HashMap<Integer, String> nodeList;
	public static int electedI=-1;
	public static int ownIdentifier;
	public static int maxIdentifier=-1;
	public static long electionStartetTime;
	public static long electionWaitTimeStartet;
	public static long T=2000;
	public static boolean startetElection=false;//as default a node has node startet an election
	public static boolean answerRecieved=false;
	public static boolean alreadySendCoordinator=false;

	
	private static synchronized void holdElection(){

		System.out.println("holdElection..");
		electionStartetTime=System.currentTimeMillis();
		while((System.currentTimeMillis()-electionStartetTime)<T){
			System.out.println("Election is running...waiting for answer");
			if(answerRecieved){
				electionStartetTime=0;//stops outer while loop
				electionWaitTimeStartet=System.currentTimeMillis();
				while((System.currentTimeMillis()-electionWaitTimeStartet)<(T+200)){
					System.out.println("Election is running...waiting for coordinator");
					if(electedI!=-1){
					  System.out.println("electedID = " + electedI);
					  electionWaitTimeStartet=0;//stops inner loop because now we have a new electedI(new admin)

					}
					try {
						Thread.sleep(200);//do not to run to often
					} catch (InterruptedException e) {	}
				}
				if(electedI==-1){//then no coordinater message has recieved. Start new election
					System.out.println("no coordinate messages recieved. Stating new election");
					sendElectionToNodes();
				}
			}
				try {
					Thread.sleep(200);//do not to run to often
				} catch (InterruptedException e) {	}
			}
		if(!answerRecieved){//no answers recieved after T(waitTime) time
			System.out.println("no answers recived. Now i am coordinator");
			sendCoordinatorToAll();
			TempController.adminTemperatureIpAddress = TempController.myIpAddress;
			TempController.adminTemperaturePort = TempController.myadminTemperaturePort;
		    TempController.makeAdmin(true);
			
			BullyAlgorithmControlller.electedI=BullyAlgorithmControlller.ownIdentifier;
		}
		
		System.out.println("Election done..");
		
	}
	
	public static synchronized void sendElectionToNodes() {
		startetElection=true;
		//setup values for the election
		answerRecieved=false;
		alreadySendCoordinator=false;
		electedI=-1;
		for (Entry<Integer, String> node : nodeList.entrySet()) {
			if (node.getKey() > ownIdentifier) {
				try {
					String[] nodeIpPort = node.getValue().split(":");
					Socket socket = new Socket(nodeIpPort[0],Integer.parseInt(nodeIpPort[1].trim()));
					AdminGetAnswerThread getAnwser= new AdminGetAnswerThread(socket);
					getAnwser.start();
				} catch (UnknownHostException e) {
					//e.printStackTrace();
				} catch (IOException e) {
					//e.printStackTrace();
				}
			}
		
		}
		holdElection();
		if(electedI!=-1){//new admin picked and safe to reset startetElection to false
			startetElection=false;
		}
	}
	public static synchronized void sendCoordinatorToAll() {

		for (Entry<Integer, String> node : nodeList.entrySet()) {
			if (node.getKey() < ownIdentifier) {
				try {
					String[] nodeIpPort = node.getValue().split(":");
					Socket socket = new Socket(nodeIpPort[0],Integer.parseInt(nodeIpPort[1].trim()));
					DataOutputStream out = new DataOutputStream(socket.getOutputStream());

					String msg = Action.COORDINATER.toString()+ ":" + ownIdentifier + ":" + TempController.myadminTemperaturePort;
					System.out.println("sending...+ " + msg);
					out.writeUTF(msg);
					socket.close();
				} catch (UnknownHostException e) {
					//e.printStackTrace();
				} catch (IOException e) {
					//e.printStackTrace();
				}
			}
		}
		
	}

	

}
